package com.example.audio_test.utils

import android.media.*
import android.os.Process
import com.example.audio_test.bean.EncoderParams
import java.lang.ref.WeakReference

/**
 * 对aac音频进行编码
 *
 * @author : Kun
 * @date : 2021/6/29
 * @time : 9:35
 */
class AACEncodeConsumer : Thread() {

    companion object {
        val MIME_TYPE = "audio/mp4a-latm"
        val TIMES_OUT = 10000L
    }

    private var audioRecord: AudioRecord? = null

    /**
     * 是否退出
     */
    private var isExit = false

    private var mMuxerRef: WeakReference<MediaMuxerUtil>? = null
    private var mParamsRef: WeakReference<EncoderParams>? = null

    private var mAudioEncoder: MediaCodec? = null
    private var newFormat: MediaFormat? = null

    private var isEncoderStarted = false

    @Synchronized
    fun setTmpuMuxer(muxer: MediaMuxerUtil, mparams: EncoderParams) {
        mMuxerRef = WeakReference(muxer)
        mParamsRef = WeakReference(mparams)

        val m = mMuxerRef!!.get()
        if (m != null && newFormat != null) {
            m.addTrack(newFormat!!, false)
        }
    }

    /**
     * 退出 停止录音
     */
    fun exit() {
        isExit = true
    }

    override fun run() {
         startAudioRecord()
        startCodec()
        while (!isExit) {
            if (mAudioEncoder != null) {
                val byteArray = ByteArray(1024)
                val readBytes = audioRecord!!.read(byteArray, 0, 1024)
                if (readBytes > 0) {
                    try {
                        encoderBytes(byteArray, readBytes)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            }
        }
        stopAudioRecord()
        stopCodec()
    }

    /**
     * 编码
     */
    private fun encoderBytes(audioBuffer: ByteArray?, readBytes: Int) {

        val inputIndex = mAudioEncoder!!.dequeueInputBuffer(TIMES_OUT)
        if (inputIndex >= 0) {
            val byteBuffer = mAudioEncoder!!.getInputBuffer(inputIndex)

            if (audioBuffer == null || readBytes <= 0) {
                mAudioEncoder!!.queueInputBuffer(
                    inputIndex,
                    0,
                    0,
                    getPTSUs(),
                    MediaCodec.BUFFER_FLAG_END_OF_STREAM
                )
            } else {
                byteBuffer!!.clear()
                byteBuffer.put(audioBuffer)
                mAudioEncoder!!.queueInputBuffer(inputIndex, 0, readBytes, getPTSUs(), 0)
            }

            val bufferInfo = MediaCodec.BufferInfo()
            var outputIndex = mAudioEncoder!!.dequeueOutputBuffer(bufferInfo, TIMES_OUT)
            while (outputIndex >= 0) {
                if (outputIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
                    //超时
                } else if (outputIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                    //变化
                } else if (outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                    //输出缓存区格式改变，通常在存储数据前且只改变一次
                    //这里设置混合器轨道，如果音频已经添加则启动混合器
                    synchronized(this) {
                        newFormat = mAudioEncoder!!.outputFormat
                        if (newFormat != null) {
                            mMuxerRef!!.get()?.addTrack(newFormat!!, false)
                        }
                    }
                } else {
                    if ((bufferInfo.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                        //数据已经被消费掉
                        bufferInfo.size = 0
                    }

                    if ((bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                        //数据流结束标志
                        break
                    }

                    val outBuffer = mAudioEncoder!!.getOutputBuffer(outputIndex)
//                    val outBuffer = outBuffers[outputIndex]
                    if (bufferInfo.size != 0) {
                        if (outBuffer == null) {
                            throw RuntimeException("encodecOutputBuffer " + outputIndex + " is null")
                        }

                        synchronized(this) {
                            newFormat = mAudioEncoder!!.outputFormat
                            if (newFormat != null) {
                                mMuxerRef!!.get()?.addTrack(newFormat!!, false)
                            }
                        }

                        if (mMuxerRef != null) {
                            mMuxerRef!!.get()?.pumpStream(outBuffer, bufferInfo, false)
                        }
                    }
                }
                mAudioEncoder!!.releaseOutputBuffer(outputIndex, false)
                outputIndex = mAudioEncoder!!.dequeueOutputBuffer(bufferInfo, TIMES_OUT)
            }
        }
    }

    /**
     * 开始编码
     */
    private fun startCodec() {
        isExit = false
        val codecInfo = selectSupportCodec(MIME_TYPE)
        if (codecInfo == null || mParamsRef == null) {
            return
        }
        try {
            mAudioEncoder = MediaCodec.createByCodecName(codecInfo.name)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        val params = mParamsRef!!.get()
        val mediaFormat = MediaFormat()
        mediaFormat.setString(MediaFormat.KEY_MIME, MIME_TYPE)
        mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, params!!.audioBitrate)
        mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, params.audioSampleRate)
        mediaFormat.setInteger(
            MediaFormat.KEY_AAC_PROFILE,
            MediaCodecInfo.CodecProfileLevel.AACObjectERLC
        )
        mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, params.audioChannelCount)
        mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 1600)

        if (mAudioEncoder != null) {
            mAudioEncoder!!.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
            mAudioEncoder!!.start()
            isEncoderStarted = true
        }
    }

    /**
     * 停止编码
     */
    private fun stopCodec() {
        if (mAudioEncoder != null) {
            mAudioEncoder!!.stop()
            mAudioEncoder!!.release()
            mAudioEncoder = null
        }
        isEncoderStarted = false
    }

    /**
     * 开始录音
     */
    private fun startAudioRecord(): Int {
        val params = mParamsRef!!.get()
        var minBufferSize = AudioRecord.getMinBufferSize(
            params!!.audioSampleRate,
            params.audioChannelConfig,
            params.audioFormat
        )
        if (minBufferSize < 1600) {
            minBufferSize = 1600
        }
        Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO)

        audioRecord = AudioRecord(
            params.audioSource,
            params.audioSampleRate,
            params.audioChannelConfig,
            params.audioFormat,
            minBufferSize
        )
        audioRecord!!.startRecording()

        return minBufferSize
    }

    /**
     * 停止录音
     */
    private fun stopAudioRecord() {
        if (audioRecord != null) {
            audioRecord!!.stop()
            audioRecord!!.release()
            audioRecord = null
        }
    }

    private fun selectSupportCodec(mimeType: String): MediaCodecInfo? {
        val mediaCodecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)
        for (codecInfo in mediaCodecList.codecInfos) {
            if (!codecInfo.isEncoder) {
                //不是编码器
                continue
            }
            for (type in codecInfo.supportedTypes) {
                if (type!!.equals(mimeType, true)) {
                    return codecInfo
                }
            }
        }
        return null
    }

    private fun getPTSUs(): Long {
        return System.nanoTime() / 1000
    }
}